package com.seezoon.domain.service;

import com.seezoon.domain.dao.mapper.DeviceInfoMapper;
import com.seezoon.domain.dao.po.DeviceInfoPO;
import com.seezoon.domain.valueobj.StatusVO;
import com.seezoon.infrastructure.exception.Assertion;
import com.seezoon.infrastructure.utils.NetUtils;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import java.time.Instant;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

@Slf4j
@Service
@RequiredArgsConstructor
@Validated
public class DeviceInfoService {

    private final DeviceInfoMapper deviceInfoMapper;
    private final DeviceStatusService deviceStatusService;
    private final String hostIp = NetUtils.getHostIp();
    @Value("${server.port}")
    private int port;

    /**
     * 设备注册，为了简单没有抽离VO
     *
     * @param deviceInfoPO
     * @return
     */
    @Transactional
    public int register(@NotNull DeviceInfoPO deviceInfoPO) {
        int affectedRows = deviceInfoMapper.insert(deviceInfoPO);
        Assertion.affectedOne(affectedRows);
        // 初始化状态表，便于后面批量更新
        StatusVO statusVO = new StatusVO();
        statusVO.setDeviceId(deviceInfoPO.getId());
        statusVO.setLatitude(0.0);
        statusVO.setLongitude(0.0);
        statusVO.setSpeed(0);
        statusVO.setDirection(0);
        statusVO.setAltitude(0);
        statusVO.setBatteryLevel((byte) 0);
        statusVO.setAlarmSignals(0L);
        statusVO.setStatusFlags(0L);
        statusVO.setMileage(0);
        statusVO.setStatusTime(Instant.now());
        deviceStatusService.insert(statusVO);
        return affectedRows;
    }

    /**
     * 上线
     *
     * @param id
     * @return
     */
    public int online(@NotNull Long id) {
        Assertion.notEmpty(hostIp, "host ip is empty");
        DeviceInfoPO row = new DeviceInfoPO();
        row.setId(id);
        row.setDeviceStatus(DeviceInfoPO.ONLINE);
        Instant now = Instant.now();
        row.setCurrentEndpoint(getCurrentEndpoint());
        row.setLastOnlineTime(now);
        row.setUpdateTime(now);
        int affectedRows = deviceInfoMapper.updateByPrimaryKeySelective(row);
        Assertion.affectedOne(affectedRows);
        return affectedRows;
    }

    /**
     * 设备心跳
     *
     * @param deviceIds 设备Ids
     * @return
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public int ping(@NotEmpty Set<Long> deviceIds) {
        return deviceInfoMapper.updateByPing(deviceIds, Instant.now());
    }

    /**
     * 按时间下线设备
     *
     * @param offlineTime 截止时间
     * @return
     */
    public int offline(@NotNull Instant offlineTime) {
        return deviceInfoMapper.offlineHeartbeatTimeout(offlineTime, Instant.now());
    }

    public String getCurrentEndpoint() {
        return hostIp + ":" + port;
    }
}
